package Thread;

import java.util.concurrent.*;

/**
 * (01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行；而CyclicBarrier则是允许N个线程相互等待。
 * (02) CountDownLatch的计数器无法被重置；CyclicBarrier的计数器可以被重置后使用，因此它被称为是循环的barrier。
 *
 * 但看完这两句话，从代码角度出发，这两者的区别我一直没有理解。1个线程等待其他线程，和N个线程相互等待，其实从某种角度来讲，
 * 意义是差不多的，总归都是到达某个触发点之后，执行所有线程。所以从我个人的角度出发，我觉得第一点更多时候只是意义上的差别，
 * 在功能上似乎没有什么区别。（如果各位有什么看法，请指正。）
 *
 * 然后我试下来，我认为两者的关键区别在于第二点，CountDownLatch一旦计数器到0，后面的线程不会再等待，无条件执行，
 * 而对于CyclicBarrier，第一轮的数量满足后，第二轮也必须达到指定的数量，才会再次执行。换成代码如下所示：
 *
 * 所以我觉得之前说的第2点，用我的理解来描述的话，应该是这样：
 *
 * (02) CountDownLatch的计数器一旦为0，无法被重置，失去原有的作用；CyclicBarrier的计数器可以被循环使用，一次循环结束后，可以继续给下一次的循环使用。
 */
public class CyclicBarrierCountDownLatch {
    public static void main(String[] args) throws InterruptedException {
        test1();
//        test2();
    }

    private static void test2() {
        final int threadCount = 3;
        ExecutorService service = Executors.newFixedThreadPool(threadCount);
        final CountDownLatch latch = new CountDownLatch(threadCount);

        //以下遍历过过程故意将threadCount+2，会发现当 i = threadCount - 1时，
        //就会触发latch的执行，for循环后续的几个线程（threadCount, threacCount + 1）会直接执行，
        //没有任何等待，因为latch已经到达0了，不再有任何作用了。
        for (int i = 0; i < threadCount + 2; i++) {
            int finalI = i;
            service.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Thread.sleep(4000);
                    System.out.println(finalI);
                    latch.countDown();
                    Thread.sleep(4000);
                    latch.await();
                    System.out.println("des");
                    return "test message";
                }
            });
        }
        service.shutdown();
    }

    private static void test1() {
        final int threadCount = 3;
        ExecutorService service = Executors.newFixedThreadPool(threadCount);

        final CyclicBarrier barrier = new CyclicBarrier(threadCount);

        //以下遍历过过程故意将threadCount+2，会发现当 i = threadCount - 1时，
        //就会触发barrier的执行，但是for循环后续的几个线程（threadCount, threacCount + 1）会一直等待，
        //因为数量是2，没有达到执行点。也就是说CyclicBarrier是循环起作用的，这个是与CountDownLatch的重要区别
        for (int i = 0; i < threadCount + 2; i++) {
            int finalI = i;
            service.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Thread.sleep(4000);
                    System.out.println(finalI);
                    barrier.await();
                    Thread.sleep(4000);
                    System.out.println("des");
                    return "test message";
                }
            });
        }
        System.out.println("end");
        service.shutdown();
    }
}
